package weavingtest;

import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import polyglot.types.SemanticException;
import polyglot.util.InternalCompilerError;
import polyglot.util.Position;
import soot.jimple.Stmt;
import soot.util.Chain;
import abc.weaving.aspectinfo.Aspect;
import abc.weaving.aspectinfo.Pointcut;
import abc.weaving.matching.BodyShadowMatch;
import abc.weaving.matching.MatchingContext;
import abc.weaving.matching.MethodPosition;
import abc.weaving.matching.NewStmtMethodPosition;
import abc.weaving.matching.ShadowMatch;
import abc.weaving.matching.ShadowType;
import abc.weaving.matching.StmtMethodPosition;
import abc.weaving.residues.AlwaysMatch;
import abc.weaving.residues.NeverMatch;
import abc.weaving.residues.Residue;

public class AspectInfoContains extends abc.weaving.aspectinfo.Pointcut {
    abc.weaving.aspectinfo.Pointcut param =
      null;
    
    public AspectInfoContains(polyglot.util.Position pos,
                              abc.weaving.aspectinfo.Pointcut param) {
        super(pos);
        this/*weavingtest.AspectInfoContains*/.param =
          param;
    }
    
    public void getFreeVars(java.util.Set result) {
        
    }
    
    public void registerSetupAdvice(abc.weaving.aspectinfo.Aspect context,
                                    java.util.Hashtable typeEnv) {
        
    }
    
    public abc.weaving.aspectinfo.Pointcut inline(java.util.Hashtable renameEnv,
                                                  java.util.Hashtable typeEnv,
                                                  abc.weaving.aspectinfo.Aspect context,
                                                  int cflowdepth) {
        abc.weaving.aspectinfo.Pointcut newParam =
          this/*weavingtest.AspectInfoContains*/.param.inline(renameEnv,
                                                              typeEnv,
                                                              context,
                                                              cflowdepth);
        if (newParam ==
              this/*weavingtest.AspectInfoContains*/.param) {
            return this;
        }
        return new weavingtest.AspectInfoContains(getPosition(),
                                                  newParam);
    }
    
    public java.lang.String toString() {
        return "contains(" +
               this/*weavingtest.AspectInfoContains*/.param.toString() +
        ")";
    }
    
    public abc.weaving.residues.Residue matchesAt(abc.weaving.matching.MatchingContext mc)
          throws polyglot.types.SemanticException {
        abc.weaving.residues.Residue ret =
          abc.weaving.residues.NeverMatch.v();
        if (!(mc.getShadowMatch() instanceof abc.weaving.matching.BodyShadowMatch)) {
            return abc.weaving.residues.NeverMatch.v();
        }
        soot.util.Chain stmtsChain =
          mc.getSootMethod().getActiveBody().getUnits();
        soot.jimple.Stmt current;
        soot.jimple.Stmt next;
        for (current =
               (soot.jimple.Stmt)
                 stmtsChain.getFirst();
             current !=
               null;
             current =
               next) {
            next =
              (soot.jimple.Stmt)
                stmtsChain.getSuccOf(current);
            abc.weaving.matching.StmtMethodPosition pos =
              new abc.weaving.matching.StmtMethodPosition(mc.getSootMethod(),
                                                          current);
            abc.weaving.matching.NewStmtMethodPosition newPos =
              new abc.weaving.matching.NewStmtMethodPosition(mc.getSootMethod(),
                                                             current,
                                                             next);
            if (doShadows(mc,
                          pos) ==
                  abc.weaving.residues.AlwaysMatch.v() ||
                  doShadows(mc,
                            newPos) ==
                    abc.weaving.residues.AlwaysMatch.v()) {
                ret =
                  abc.weaving.residues.AlwaysMatch.v();
                java.lang.System/*java.lang.System*/.out.println(mc.getSootMethod().toString());
                break;
            }
        }
        return ret;
    }
    
    public abc.weaving.residues.Residue doShadows(abc.weaving.matching.MatchingContext mc,
                                                  abc.weaving.matching.MethodPosition pos)
          throws polyglot.types.SemanticException {
        abc.weaving.residues.Residue ret =
          abc.weaving.residues.NeverMatch.v();
        for (java.util.Iterator i =
               abc.main.Main.v().getAbcExtension().shadowTypes();
             i.hasNext();
             ) {
            abc.weaving.matching.ShadowType st =
              (abc.weaving.matching.ShadowType)
                i.next();
            abc.weaving.matching.ShadowMatch sm;
            try {
                sm =
                  st.matchesAt(pos);
            }
            catch (polyglot.util.InternalCompilerError e) {
                throw new polyglot.util.InternalCompilerError(e.message(),
                                                              e.position() ==
                                                                null ? abc.polyglot.util.ErrorInfoFactory.getPosition(pos.getContainer(),
                                                                                                                      pos.getHost()) : e.position(),
                                                              e.getCause());
            }
            catch (java.lang.Throwable e) {
                throw new polyglot.util.InternalCompilerError("Error while looking for join point shadow",
                                                              abc.polyglot.util.ErrorInfoFactory.getPosition(pos.getContainer(),
                                                                                                             pos.getHost()),
                                                              e);
            }
            abc.weaving.residues.Residue currMatch =
              this/*weavingtest.AspectInfoContains*/.param.matchesAt(new abc.weaving.matching.MatchingContext(mc.getWeavingEnv(),
                                                                                                              mc.getSootClass(),
                                                                                                              mc.getSootMethod(),
                                                                                                              sm));
            if (currMatch ==
                  abc.weaving.residues.AlwaysMatch.v()) {
                ret =
                  currMatch;
                break;
            }
        }
        assert ret ==
                 abc.weaving.residues.AlwaysMatch.v() ||
          ret ==
            abc.weaving.residues.NeverMatch.v(): "Error: Dynamic match on contains() parameter";
        return ret;
    }
}
